#include "jvariant.h"
#include <JXQCore/JDebug>
#include <cstring>
#include <cstdlib>

namespace JXQ
{

JVariantData::JVariantData(const JVariantData &other)
{
	if( data != nullptr )
		JMeta::deleteObject(typeInfo->name(), data);

	typeInfo = other.typeInfo;
	data = JMeta::copyObject(other.typeInfo->name(), other.data);
}

JVariantData::~JVariantData()
{
	if( data != nullptr )
		JMeta::deleteObject(typeInfo->name(), data);
}

/*--------------------------------------------------------------------------------*/

JVariant::JVariant() :
	pData(new JVariantData())
{
	pData->typeInfo = &JTypeInfo::voidType;
	pData->data = nullptr;
}

JVariant::JVariant(JVariant &other) :
	pData(new JVariantData(*other.pData))
{

}

JVariant::JVariant(const JVariant &other) :
	pData(new JVariantData(*other.pData))
{

}

JVariant::JVariant(JVariant &&other)
{
	pData = other.pData;
	other.pData = nullptr;
}

JVariant::~JVariant()
{
	if( pData != nullptr )
		delete pData;
}

const JVariant &JVariant::operator=(JVariant &other)
{
	delete pData;
	pData = new JVariantData(*other.pData);
	return *this;
}

const JVariant &JVariant::operator=(const JVariant &other)
{
	delete pData;
	pData = new JVariantData(*other.pData);
	return *this;
}

const JVariant &JVariant::operator=(JVariant &&other)
{
	delete pData;
	pData = other.pData;
	other.pData = nullptr;
	return *this;
}

bool JVariant::operator==(const JVariant &other) const
{
	return pData->typeInfo->operator==(*other.pData->typeInfo);
}

const JTypeInfo &JVariant::type() const
{
	return *pData->typeInfo;
}

bool JVariant::isEmpty() const
{
	return pData->data == nullptr;
}

void JVariant::clear()
{
	pData->typeInfo = &JTypeInfo::voidType;
	pData->data = nullptr;
}

bool JVariant::toBool() const
{ return value<bool>(); }

char JVariant::toChar() const
{ return value<char>(); }

wchar_t JVariant::toWChar_t() const
{ return value<wchar_t>(); }

uint8_t JVariant::toUChar() const
{ return value<unsigned char>(); }

int16_t JVariant::toShort() const
{ return value<short>(); }

uint16_t JVariant::toUShort() const
{ return value<short>(); }

int JVariant::toInt() const
{ return value<int>(); }

unsigned int JVariant::toUint() const
{ return value<unsigned int>(); }

long JVariant::toLong() const
{ return value<long>(); }

unsigned long JVariant::toULong() const
{ return value<unsigned long>(); }

int64_t JVariant::toLLong() const
{ return value<long long>(); }

uint64_t JVariant::toULLong() const
{ return value<unsigned long long>(); }

float JVariant::toFloat() const
{ return value<float>(); }

double JVariant::toDouble() const
{ return value<double>(); }

long double JVariant::toLDouble() const
{ return value<long double>(); }

JBasicString<char> JVariant::toStringC() const
{ return value<JBasicString<char>>(); }

JStringW JVariant::toStringW() const
{ return value<JStringW>(); }

JString JVariant::toString() const
{ return value<JString>(); }

JBasicStringList<char> JVariant::toStringCList() const
{ return value<JBasicStringList<char>>(); }

JStringWList JVariant::toStringWList() const
{ return value<JStringWList>(); }

JStringList JVariant::toStringList() const
{ return value<JStringList>(); }

JXQLIB_EXPORT JDebug &operator<<(JDebug &d, const JVariant *var)
{
	d << ("JXQ::JVarent::type = " + var->type().name()).c_str();
	const auto &type = var->type();

	if( type.isPointer() )
		d << var->value<void*>();

	else if( type.isPrimitive() )
	{
		d << ", value =";
		if( type == typeid(char) )
			d << var->toChar();
		else if( type == typeid(wchar_t) )
			d << var->toWChar_t();

		else if( type == typeid(float) )
			d << var->toFloat();
		else if( type == typeid(double) )
			d << var->toDouble();
		else if( type == typeid(long double) )
			d << var->toLDouble();

		else if( type.name().find("unsigned") != std::string::npos )
			d << var->toLLong();
		else
			d << var->toULLong();
	}

	else if( type == typeid(char*) or type == typeid(const char*) )
		d << ", value =" << var->value<const char*>();
	else if( type == typeid(std::basic_string<char>) )
		d << ", value =" << var->value<std::basic_string<char>>();
	else if( type == typeid(JBasicString<char>) )
		d << ", value =" << var->value<JBasicString<char>>();

	else if( type == typeid(wchar_t*) or type == typeid(const wchar_t*) )
		d << ", value =" << var->value<const wchar_t*>();
	else if( type == typeid(std::basic_string<wchar_t>) )
		d << ", value =" << var->value<std::basic_string<wchar_t>>();
	else if( type == typeid(JBasicString<wchar_t>) )
		d << ", value =" << var->value<JBasicString<wchar_t>>();

	return d;
}

JXQLIB_EXPORT JDebug &operator<<(JDebug &&d, const JVariant *var)
{
	return d << var;
}

JXQLIB_EXPORT JDebug &operator<<(JDebug &d, const JVariant &var)
{
	return d << &var;
}

JXQLIB_EXPORT JDebug &operator<<(JDebug &&d, const JVariant &var)
{
	return d << &var;
}

} //namespace JXQ
